﻿using Newtonsoft.Json;
using ServiceMonitor.Core;
using ServiceMonitor.Model;
using ServiceMonitor.Utils;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace ServiceMonitor.Services
{
    public sealed class MonitoringService
    {
        public event EventHandler<ServiceStatusChangedEventArgs> StatusChanged;

        private readonly Action<MonitorConfig, String> _logger;
        private readonly string _configPath;
        private readonly Timer _monitoringTimer;
        private List<MonitorConfig> _configs = new List<MonitorConfig>();
        private readonly ConcurrentDictionary<int, JarProcessInfo> _jarProcesses = new ConcurrentDictionary<int, JarProcessInfo>();
        private readonly Dictionary<int, string> _lastStatuses = new Dictionary<int, string>();
        private bool _isMonitoring;
        private int _globalInterval = 30; // 默认全局检查间隔(秒)



        public MonitoringService(Action<MonitorConfig, String> logger, string configPath)
        {
            _logger = logger;
            _configPath = configPath;
            _monitoringTimer = new Timer(CheckServiceStatus, null, Timeout.Infinite, Timeout.Infinite);
        }

        public void StartMonitoring(int checkInterval = 30)
        {
            if (_isMonitoring) return;

            _globalInterval = checkInterval;
            _isMonitoring = true;
            _monitoringTimer.Change(0, checkInterval * 1000);
            _logger(null, "监控服务已启动");
        }

        public void StopMonitoring()
        {
            if (!_isMonitoring) return;

            _isMonitoring = false;
            _monitoringTimer.Change(Timeout.Infinite, Timeout.Infinite);
            _logger(null, "监控服务已停止");

            // 停止所有JAR进程
            foreach (var kvp in _jarProcesses)
            {
                StopJar(kvp.Key);
            }
        }

        public List<MonitorConfig> GetAllConfigs()
        {
            return new List<MonitorConfig>(_configs);
        }

        public void AddConfig(MonitorConfig config)
        {
            _configs.Add(config);
            _lastStatuses[config.Id] = "未检测";
            SaveConfigs();
        }

        public void UpdateConfig(MonitorConfig config)
        {
            var existingConfig = _configs.FirstOrDefault(c => c.Id == config.Id);
            if (existingConfig != null)
            {
                _configs.Remove(existingConfig);
                _configs.Add(config);
                SaveConfigs();
            }
        }

        public void RemoveConfig(int id)
        {
            StopJar(id);
            var config = _configs.FirstOrDefault(c => c.Id == id);
            if (config != null)
            {
                _configs.Remove(config);
                SaveConfigs();
            }
        }

        public void SaveConfigs()
        {
            try
            {
                string directory = Path.GetDirectoryName(_configPath);
                if (!Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }

                string json = JsonConvert.SerializeObject(_configs);
                File.WriteAllText(_configPath, json);
                _logger(null, "配置已保存");
            }
            catch (Exception ex)
            {
                _logger(null, "保存配置失败: " + ex.Message);
            }
        }

        public void LoadConfigs()
        {
            try
            {
                if (!File.Exists(_configPath))
                {
                    _logger(null, $"配置文件不存在: {_configPath}");
                    return;
                }

                string json = File.ReadAllText(_configPath);
                _configs = JsonConvert.DeserializeObject<List<MonitorConfig>>(json) ?? new List<MonitorConfig>();

                foreach (var config in _configs)
                {
                    _lastStatuses[config.Id] = "配置已加载";
                }

                _logger(null, $"已加载 {_configs.Count} 个监控配置");
            }
            catch (Exception ex)
            {
                _logger(null, $"加载配置失败: {ex.Message}");
            }
        }

        public void StartJar(MonitorConfig config)
        {
            if (!config.IsActive) return;
            if (config.Type != MonitorType.StringBoot) return;

            StopJar(config.Id);

            try
            {
                var process = new Process();
                process.StartInfo.FileName = "java";
                process.StartInfo.Arguments = $"{config.JavaArgs} -jar \"{config.JarPath}\"";
                process.StartInfo.WorkingDirectory = string.IsNullOrWhiteSpace(config.WorkingDirectory)
                    ? Path.GetDirectoryName(config.JarPath)
                    : config.WorkingDirectory;
                process.StartInfo.UseShellExecute = false;
                process.StartInfo.RedirectStandardOutput = true;
                process.StartInfo.RedirectStandardError = true;
                process.StartInfo.CreateNoWindow = true;
                process.EnableRaisingEvents = true;

                // 添加日志重定向
                process.OutputDataReceived += (sender, e) =>
                {
                    if (!string.IsNullOrWhiteSpace(e.Data))
                    {
                        _logger(config, $"[JAR #{config.Id}] {e.Data}");
                    }
                };

                process.ErrorDataReceived += (sender, e) =>
                {
                    if (!string.IsNullOrWhiteSpace(e.Data))
                    {
                        _logger(config, $"[JAR #{config.Id} ERROR] {e.Data}");

                        // 收集错误信息
                        if (_jarProcesses.TryGetValue(config.Id, out JarProcessInfo processInfo))
                        {
                            lock (processInfo.ErrorBuffer)
                            {
                                // 为每行添加时间戳（仅当日志间隔超过5秒时）
                                string timestamp = DateTime.Now.ToString("HH:mm:ss");
                                if (timestamp != processInfo.LastLineTimestamp)
                                {
                                    processInfo.LastLineTimestamp = timestamp;
                                    processInfo.ErrorBuffer.AppendLine();
                                    processInfo.ErrorBuffer.Append($"{timestamp} ");
                                }
                                processInfo.ErrorBuffer.AppendLine(e.Data);

                                // 限制缓存大小
                                if (processInfo.ErrorBuffer.Length > 4096)
                                {
                                    processInfo.ErrorBuffer.Remove(0, 1024);
                                }
                            }
                        }
                    }
                };

                process.Exited += (sender, e) =>
                {
                    if (_jarProcesses.TryRemove(config.Id, out JarProcessInfo processInfo))
                    {
                        processInfo.Process.Dispose();
                        UpdateStatus(config.Id, $"进程已退出");
                    }
                };

                process.Start();
                process.BeginOutputReadLine();
                process.BeginErrorReadLine();

                var jarInfo = new JarProcessInfo
                {
                    Process = process,
                    StartTime = DateTime.UtcNow
                };

                _jarProcesses[config.Id] = jarInfo;
                UpdateStatus(config.Id, "JAR进程已启动");
            }
            catch (Exception ex)
            {
                UpdateStatus(config.Id, $"启动JAR失败: {ex.Message}");
            }
        }

        public void StopJar(int serviceId)
        {
            var existingConfig = _configs.FirstOrDefault(c => c.Id == serviceId);
            if (existingConfig != null && existingConfig.Type == MonitorType.StringBoot)
            {
                // 通过检测SpringBoot绑定的端口来停止JAR进程
                PortProcessTerminator.KillProcessByPort(existingConfig.HttpPort);

            }
            if (_jarProcesses.TryRemove(serviceId, out JarProcessInfo processInfo))
            {
                try
                {
                    if (!processInfo.Process.HasExited)
                    {
                        processInfo.Process.Kill();
                        processInfo.Process.WaitForExit(5000);
                    }
                    processInfo.Process.Dispose();
                }
                catch (Exception ex)
                {
                    _logger(null, $"停止JAR #{serviceId} 失败: {ex.Message}");
                }
                UpdateStatus(serviceId, "JAR进程已停止");
            }
        }

        private void CheckServiceStatus(object state)
        {
            if (!_isMonitoring) return;

            foreach (var config in _configs)
            {
                if (!config.IsActive) continue;

                try
                {
                    switch (config.Type)
                    {
                        case MonitorType.Port:
                            CheckPortStatus(config);
                            break;

                        case MonitorType.Http:
                            CheckHttpStatus(config);
                            break;

                        case MonitorType.StringBoot:
                            CheckJarStatus(config);
                            break;
                    }
                }
                catch (Exception ex)
                {
                    UpdateStatus(config.Id, $"检测错误: {ex.Message}");
                }
            }
        }

        private void CheckPortStatus(MonitorConfig config)
        {
            try
            {
                using (var client = new TcpClient())
                {
                    // 设置1秒超时
                    var result = client.BeginConnect(config.Host, config.Port, null, null);
                    bool success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(1));
                    if (success && client.Connected)
                    {
                        client.EndConnect(result);
                        UpdateStatus(config.Id, $"端口 {config.Port} 连接成功");
                    }
                    else
                    {
                        client.Close();
                        throw new TimeoutException("连接超时");
                    }
                }
            }
            catch (Exception ex)
            {
                UpdateStatus(config.Id, $"端口检测失败: {ex.Message}");
            }
        }

        private void CheckHttpStatus(MonitorConfig config)
        {
            try
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(config.Url);
                request.Timeout = config.Timeout;
                request.Method = "HEAD"; // 使用更轻量的HEAD请求

                using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
                {
                    int statusCode = (int)response.StatusCode;
                    if (statusCode == (int)config.ExpectedStatus)
                    {
                        UpdateStatus(config.Id, $"HTTP状态: {statusCode}");
                    }
                    else
                    {
                        throw new Exception($"预期状态码 {config.ExpectedStatus}, 实际: {statusCode}");
                    }
                }
            }
            catch (Exception ex)
            {
                UpdateStatus(config.Id, $"HTTP检测失败: {ex.Message}");
            }
        }

        private void CheckJarStatus(MonitorConfig config)
        {
            // 1. 首先检查进程是否存在
            if (!_jarProcesses.TryGetValue(config.Id, out JarProcessInfo processInfo))
            {
                UpdateStatus(config.Id, "进程未运行");
                StartJar(config);
                return;
            }
            // 2. 检查进程状态
            if (processInfo.Process.HasExited)
            {
                _jarProcesses.TryRemove(config.Id, out _);
                UpdateStatus(config.Id, $"进程已退出, 代码: {processInfo.Process.ExitCode}");
                StartJar(config);
                return;
            }
            // 3. 检查端口是否已被监听（关键改进）
            var portListeningStatus = CheckPortListening(config.HttpPort);
            bool isPortListening = portListeningStatus.IsListening;
            string portStatusMessage = portListeningStatus.Message;

            // 4. 检查启动超时
            if ((DateTime.UtcNow - processInfo.StartTime).TotalMinutes > 3)
            {
                ProcessStartTimeout(config, processInfo, isPortListening);
                return;
            }
            // 5. 基于端口状态决定下一步操作
            if (!isPortListening)
            {
                UpdateStatus(config.Id, "启动中: 端口尚未监听");
                return;
            }
            // 6. 执行健康检查
            bool isHealthy = CheckJarHealthEndpoint(config);
            UpdateStatus(config.Id, isHealthy ? "运行正常 (健康检查通过)" : "运行中 (健康端点无响应)");
        }

        public class A
        {
            public A(bool isListening, string message)
            {
                this.IsListening = isListening;
                this.Message = message;
            }
            public bool IsListening { get; set; }
            public string Message { get; set; }
        }
        // 专用的端口监听检测方法
        private A CheckPortListening(int port)
        {
            if (port <= 0) return new A(false, "未配置有效端口");
            try
            {
                // 使用.NET内置类快速检查端口状态
                IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
                IPEndPoint[] listeners = ipGlobalProperties.GetActiveTcpListeners();

                bool isListening = listeners.Any(endPoint => endPoint.Port == port);
                return new A(isListening, isListening ? $"端口 {port} 正在监听" : $"端口 {port} 未监听");
            }
            catch (Exception ex)
            {
                return new A(false, $"端口检测错误: {ex.Message}");
            }
        }

        // 处理启动超时逻辑
        private void ProcessStartTimeout(MonitorConfig config, JarProcessInfo processInfo, bool isPortListening)
        {
            string statusMessage = "启动超时 (>3分钟)";

            // 分析错误日志
            AnalyzeLogAndUpdateStatus(config, processInfo, ref statusMessage);

            // 添加端口状态信息
            statusMessage += " - " + (isPortListening ? "端口已监听，但服务未就绪" : "端口未监听");

            // 更新状态
            UpdateStatus(config.Id, statusMessage);

            // 如果端口没有监听，尝试重启应用
            if (!isPortListening)
            {
                AttemptRestartJar(config);
            }
        }

        // 优化日志分析方法
        private void AnalyzeLogAndUpdateStatus(MonitorConfig config, JarProcessInfo processInfo, ref string statusMessage)
        {
            string errorLogContent = GetErrorLogContent(processInfo);
            if (!string.IsNullOrEmpty(errorLogContent))
            {
                string detectedIssue = DetectCommonIssues(errorLogContent);
                if (!string.IsNullOrEmpty(detectedIssue))
                {
                    statusMessage += $", {detectedIssue}";
                }
            }
        }
        // 获取错误日志内容
        private string GetErrorLogContent(JarProcessInfo processInfo)
        {
            lock (processInfo.ErrorBuffer)
            {
                return processInfo.ErrorBuffer.ToString();
            }
        }

        // 检测常见问题
        private string DetectCommonIssues(string errorLog)
        {
            if (errorLog.IndexOf("Failed to configure a DataSource", StringComparison.OrdinalIgnoreCase) >= 0)
            {
                return "数据库配置错误";
            }
            if (errorLog.IndexOf("Port in use", StringComparison.OrdinalIgnoreCase) >= 0 ||
                errorLog.IndexOf("BindException", StringComparison.OrdinalIgnoreCase) >= 0)
            {
                return "端口被占用";
            }
            if (errorLog.IndexOf("FileNotFoundException", StringComparison.OrdinalIgnoreCase) >= 0)
            {
                return "文件未找到";
            }
            if (errorLog.IndexOf("DataSource", StringComparison.OrdinalIgnoreCase) >= 0 &&
                errorLog.IndexOf("not specified", StringComparison.OrdinalIgnoreCase) >= 0)
            {
                return "数据源未配置";
            }

            return "";
        }

        private void AttemptRestartJar(MonitorConfig config)
        {
            try
            {
                _logger(config, $"尝试重启服务 #{config.Id}: {config.Name}");
                StopJar(config.Id);
                Thread.Sleep(2000); // 等待2秒
                StartJar(config);
            }
            catch (Exception ex)
            {
                UpdateStatus(config.Id, $"重启失败: {ex.Message}");
            }
        }

        private bool CheckJarHealthEndpoint(MonitorConfig config)
        {
            try
            {
                // 尝试可能的健康检查端点
                string[] endpoints = {
                    $"http://localhost:{config.HttpPort}/actuator/health",
                    $"http://localhost:{config.HttpPort}/health",
                    "http://localhost:8080/actuator/health",
                    "http://localhost:8080/health"
                };

                foreach (string url in endpoints)
                {
                    try
                    {
                        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                        request.Timeout = 2000; // 快速检查
                        request.Method = "GET";

                        using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
                        using (Stream stream = response.GetResponseStream())
                        {
                            if (stream != null)
                            {
                                using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
                                {
                                    string jsonResponse = reader.ReadToEnd();

                                    // 简单判断健康状态
                                    if (jsonResponse.IndexOf("\"status\":\"UP\"", StringComparison.OrdinalIgnoreCase) >= 0 ||
                                        jsonResponse.IndexOf("UP", StringComparison.OrdinalIgnoreCase) >= 0)
                                    {
                                        return true;
                                    }

                                    if (jsonResponse.Length > 100)
                                    {
                                        jsonResponse = jsonResponse.Substring(0, 100) + "...";
                                    }
                                    _logger(config, $"JAR #{config.Id}健康检查失败: {jsonResponse}");
                                }
                            }
                        }
                        return false;
                    }
                    catch (WebException)
                    {
                        // 尝试下一个端点
                        continue;
                    }
                }
            }
            catch (Exception ex)
            {
                _logger(config, $"JAR #{config.Id}健康检查失败: {ex.Message}");
            }

            return false;
        }

        private void UpdateStatus(int serviceId, string message)
        {
            // 限制重复消息
            if (_lastStatuses.TryGetValue(serviceId, out string lastStatus) &&
                lastStatus == message)
            {
                return;
            }

            _lastStatuses[serviceId] = message;

            // 触发事件
            var handler = StatusChanged;
            if (handler != null)
            {
                handler(this, new ServiceStatusChangedEventArgs(serviceId, message));
            }
        }
    }

    public class ServiceStatusChangedEventArgs : EventArgs
    {
        public int ConfigId { get; }
        public string Message { get; }

        public ServiceStatusChangedEventArgs(int configId, string message)
        {
            ConfigId = configId;
            Message = message;
        }
    }
}
